#include "ReservationServer.h"
#include "../CommonUtil/Util.h"
#include "BusinessLogic.h"

CReservationServer::CReservationServer()
{
	m_hServThrd = NULL;

	WORD wVersionRequested;
	WSADATA wsaData;
	int wsaerr;
	wVersionRequested = MAKEWORD(2, 2);
	wsaerr = WSAStartup(wVersionRequested, &wsaData);
	if (wsaerr != 0)
		throw CException("WSAStartup failed");

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )
	{
		WSACleanup();
		throw CException("WSAStartup failed");
	}
}

CReservationServer::~CReservationServer(void)
{
	WSACleanup();
}

void CReservationServer::stop()
{
	closesocket(m_listenSock);
	WaitForSingleObject(m_hServThrd, INFINITE);

	for (vector<CUser*>::iterator it = m_users.begin();
		it != m_users.end(); it++)
	{
		CUser* pUser = *it;
		pUser->Stop();
	}

	bool bAllStopped = true;

	do
	{
		Sleep(100);
		for (vector<CUser*>::iterator it = m_users.begin();
			it != m_users.end(); it++)
		{
			CUser* pUser = *it;
			if (!pUser->IsStopped())
			{
				bAllStopped = false;
				break;
			}
		}
	}
	while (!bAllStopped);

	for (vector<CUser*>::iterator it = m_users.begin();
		it != m_users.end(); it++)
	{
		CUser* pUser = *it;
		delete pUser;
	}
}

void CReservationServer::worker(void* pParam)
{
	CReservationServer* pServ = (CReservationServer*)pParam;

	sockaddr_in addrClnt;
	int nLen = sizeof(addrClnt);
	SOCKET sock = -1;
	while ((sock = accept(pServ->m_listenSock, (sockaddr*)&addrClnt, &nLen)) > 0)
	{
		//Clean the disconnected clients
		for (vector<CUser*>::iterator it = pServ->m_users.begin();
			it != pServ->m_users.end();)
		{
			CUser* pUser = *it;
			if (!pUser->IsStopped())
				it++;
			else
			{
				it = pServ->m_users.erase(it);
				delete pUser;
			}
		}

		CUser* pUser = new CUser(sock);
		if (pUser != NULL) 
			(pServ->m_users).push_back(pUser);

		if (pUser != NULL)
			pUser->Start();
	}
}

void CReservationServer::start(unsigned short usPort, const char* szDSN)
{
	if (!CBusinessLogic::GetInstance().ConnDataBase(szDSN))
		throw CException("Can not connect to the data source specified");

	m_listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	sockaddr_in servAddr;
	memset(&servAddr, 0, sizeof(servAddr));

	servAddr.sin_family = AF_INET;                
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
	servAddr.sin_port = htons(usPort);     

	if (bind(m_listenSock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
		throw CException("Bind server socket failed");

	if (listen(m_listenSock, 500) < 0)
		throw CException("Listening failed");

	m_hServThrd = (HANDLE)_beginthread(CReservationServer::worker, 0, (void*)this);
}
